iT邦幫忙

2024 iThome 鐵人賽

DAY 24
1
Python

從概念到應用:Python實戰開發學習之旅系列 第 24

[Day23] Python專案 - 網頁開發 - (2) 高速的服務提供者Fast API

  • 分享至 

  • xImage
  •  

目標

https://ithelp.ithome.com.tw/upload/images/20241008/20121052eyGuHKCeeQ.png
今天的目標很明顯了

會介紹Fast API
其中會想跟大家探討

其實網頁後端框架千百種光是程式語言(C#、PHP、Nodejs、Go...)
就有很多對手在跟python打架了

為什麼會想選Python的Fast API/images/emoticon/emoticon37.gif

今天會學到

1.評估框架的選擇
2.Fast API 起手式

1.評估框架的選擇

1.1 團隊&個人開發者必須評估

在決定使用哪個後端框架時,應綜合考慮專案需求技術支援團隊背景效能生態系統等因素。這樣可以確保所選技術不僅能滿足當前需求,還能為未來的增長和變化提供足夠的支持。

1. 專案需求

功能需求:明確了解專案的功能需求,例如是否需要即時通訊、數據處理或是高並發支持。這將幫助您選擇最適合的框架。
數據類型:考慮將要處理的數據類型,某些框架在處理特定數據(如結構化或非結構化數據)上表現更佳。

2. 技術支援

社群與文檔:選擇一個有活躍社群和良好文檔支持的框架,可以獲得更多資源和幫助。例如,Django 和 Flask 在 Python 生態系統中擁有強大的社群支持。
更新頻率:框架的持續更新和維護情況,能影響到安全性和新功能的引入。

3. 團隊背景

開發者經驗:團隊對特定語言或框架的熟悉程度會影響開發效率。如果團隊已經熟悉某種語言,選擇相關的框架將更為高效。
培訓需求:如果團隊需要學習新技術,這可能會增加初期開發的時間和成本。

4. 效能

性能測試:不同框架在性能上的表現可能有所不同。例如,Node.js 因其非阻塞 I/O 模型而在高並發情況下表現優異,而 Django 雖然功能強大,但在某些情況下可能速度較慢。
擴展性:考慮未來的擴展需求,某些框架如 Flask 提供了極大的靈活性,適合構建微服務架構。

5. 生態系統

第三方庫和工具:評估框架周圍的生態系統,包括可用的第三方庫、工具和插件。這可以加快開發過程並提高功能實現的便利性。

綜合評比我們可以得到

評估項目 說明 是否滿足
專案需求 FastAPI 特別適合開發RESTful API,提供簡單的路由設計與自動化文檔生成,非常適合需要API開發的專案。
技術支援 FastAPI 擁有活躍的社群支援,文檔詳細,且支持多數主流框架與資料庫,可以在技術上有良好的支援。
團隊背景 若團隊已有Python基礎,FastAPI學習曲線較低。對於需要熟悉異步操作的情況,可能需要一定學習時間。
效能 FastAPI 使用異步I/O,性能非常高,接近Node.js、Go等其他高效能框架。適合需要處理大量並發的專案。
生態系統 FastAPI 可以輕鬆集成到Python的廣泛生態系統中,如與Pandas、SQLAlchemy等工具整合,但比Flask生態略少。

1.2 個人開發者必須評估

前面是以1.1團隊為主,雖說只要公司or老闆一句話我們就是用XXX框架就定案了
但如果是可商量的情況下還是要做完整評估喔~!/images/emoticon/emoticon29.gif

1. 市場需求

公司需求:選擇市場上熱門、企業常用的技術或框架,可以增加求職的機會。查看各大招聘網站或技術趨勢報告(如Stack Overflow、GitHub的年報)可以幫助了解目前哪些框架最受歡迎。
實際應用:根據想進入的行業(如Web開發、數據分析、AI/ML等),選擇該領域常見的框架。例如,如果你希望進入Web開發領域,學習FastAPI、Flask、Django這類Python框架是很有幫助的。

2. 薪水高低

薪資水平:研究各種技術的市場價值。通常,較新且技術需求高的框架,其開發人員薪水也會較高。根據各地區的薪資報告、招聘網站的數據,查詢特定框架的開發人員薪資範圍,可以幫助你選擇學習那些薪酬高的技術。

3. 社群支持

社群活躍度:選擇有活躍社群支持的框架可以幫助你快速學習和解決問題。框架的GitHub issues數量、Stack Overflow問答數量、官方文檔的完整度等都能反映其社群的活躍程度和技術支持的好壞。
資源多寡:是否有豐富的學習資源,如教程、書籍、線上課程、官方範例等,這將直接影響學習效率。像是FastAPI、Flask、Django等都有大量資源,適合自學者。
其他考量因素:

4. 學習曲線

一些框架簡單易上手(如Flask),適合初學者。而像Django這樣的框架功能強大,但學習曲線稍陡,需要更多時間學習。

5.未來發展前景

選擇有長期發展潛力的框架可以保障你未來的技術投資不會過時。例如,FastAPI因為其異步支持和高性能逐漸被更多公司採用,有良好的發展潛力。

評估項目 說明 FastAPI 適合嗎?
市場需求 FastAPI 是一個新興框架,越來越多公司採用,特別是在需要高效能的API開發上。採用公司如 Microsoft、Netflix、Uber。 ✔️
技術支援 社群活躍度高,有豐富的文檔和教程,支持異步功能,能滿足多數現代Web開發的技術需求。 ✔️
學習背景 如果有Python基礎,學習FastAPI相對容易,且對Django/Flask開發者友好。到這個章節相信大家都對Python熟悉了XDD ✔️
效能 FastAPI 是基於Starlette和Pydantic的異步框架,效能極高,適合構建高效能的API,性能上優於Flask和Django。 ✔️
生態系統 FastAPI 擁有完整的生態系統,與許多庫和工具(如ORM、OAuth)兼容,且與Python的其他生態如Pandas、NumPy兼容。 ✔️

1.3 Roni的建議框架!?

以上兩點都是客觀評論
接下來是我Roni主觀的選擇了~

我會根據上述兩點綜合評估選擇下面四種來學習
根據不同情境來使用不同語言的框架來接案或是滿足老闆需求

其實這些語言能達到的都可以互通比如說
Nodejs(爬蟲) <=> Python(爬蟲)
Go(web microservice) <=> Nodejs
...但我想要把那個情境下綜合評估最強CP值最高的框架拿來用XDD/images/emoticon/emoticon08.gif

以下評論為投資理財分析,不構成投資建議!?

技術 適用場景 使用理由
NestJS 非同步高效能應用、微服務架構 基於 TypeScript,內建微服務支援,適合構建輕量且可擴展的非同步應用,並且擁有良好的 Node.js 生態整合。
FastAPI 資料科學應用,API 開發 支援異步程式設計,與 Python 生態系統(如 Scikit-learn、Pandas 等)無縫整合,適合快速構建資料科學應用的 API。
Spring Boot 企業級應用建置、微服務、大規模系統開發 被廣泛應用於企業級應用的後端開發,具備強大的企業工具支援,如安全性、可擴展性和資料庫集成。
C# (.NET Core) 微軟技術棧整合專案,如 Azure 或 Office 365 與微軟生態系統整合良好,C# 和 .NET Core 支援跨平台應用,適合各種與微軟服務相關的現代應用程式開發。

我會簡單分成

  1. 開發高效能API微服務: Nestjs
  2. 資料科學: Fast API 跟其他套件
  3. 企業開發: spring boot or C#

微服務不選Go的原因是因為沒有class(作者不太喜歡繼承這個OOP特性)跟套件相對python還是少。
強調並不是Go不好,但是就跟工程師有擅長的位置,語言也有擅長的處理情境

Python也有許多框架,選擇Fast API對某些團隊來說也不一定是最好的
但是對我來說,我需要一個專門處理資料科學、AI界接的微服務是必選一個python backend framework
那麼不希望Django學太多技術債(寧願把時間花在spring或是C#框架上)
Flask相較Fast API 也不夠快速
所以Fast 也變成首選

**軟體開發心聲 - PHP的開發者 **

就像前面說的有些人會說
沒有Golang的爆發、JAVA的生態、JS的異步處理
給人家感覺PHP就像運動選手中,跑步不快(go)、身體不夠強壯(java)、反應不夠(js)
Laravel (PHP) 並沒有不好 : 他也有適合的天地,Sass 、MVP(Minimum Viable Product)系統。
他也可以像是跳水員,優雅而且特定的展示屬於自己的舞台。/images/emoticon/emoticon47.gif

2.Fast API 起手式

這張章節會簡介什麼是REST API 以及會使用到的必要知識。

先麻煩個未安裝相關套件吧~!!

pip install fastapi uvicorn pydantic

2.1 REST API介紹

https://ithelp.ithome.com.tw/upload/images/20241008/20121052nuqoH8lmRm.png

這個觀念我很推薦看這位大師的說明
https://www.linkedin.com/pulse/principles-best-practices-rest-api-design-omar-ismail/

這邊會精簡成只使用到必要的需求來創造API

https://ithelp.ithome.com.tw/upload/images/20241008/20121052aJHyP2NKlv.png

項目 說明
Headers HTTP 標頭包含請求的元數據,為伺服器提供請求的額外資訊。重要標頭包括:User-Agent(發出請求的客戶端資訊)、Authorization(用於驗證身份)、Content-Type(請求體的媒介類型)、Cookie(包含用戶的會話資料)
HTTP Methods 指明對資源的操作類型。常見方法包括:GET(獲取資料)、POST(提交資料)、PUT(更新資源)、DELETE(刪除資源)
URL 指明請求的目標資源,主要包括:IP 或 Domain(資源所在的伺服器地址)、Port(端口號,HTTP 默認 80,HTTPS 默認 443)、Resource-Oriented(具體資源路徑)
Body 請求體用於攜帶額外資料,常見格式包括:JSON(結構化資料)、Form Data(表單數據)、File(上傳檔案)

2.2 Fast API Create & Get

今天的目標很簡單
需求: 建立兩隻API(POST 跟GET )

POST API的需求是

  • 讀取customer.json檔案資料
  • 從前端接受資料
  • 檢查是否Json file 有相同ID ,若有要回傳重複ID
  • 沒有重複會新增到JSON file裡面

https://ithelp.ithome.com.tw/upload/images/20241008/20121052tCrkk4JXdk.png

main.py

import json
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

# 顧客資料模型
class Customer(BaseModel):
    id: int
    name: str
    email: str
    address: str = None  

# 讀取顧客資料
def read_customers():
    try:
        with open('customer.json', 'r', encoding='utf-8') as file:
            return json.load(file)
    except FileNotFoundError:
        return []

# 寫入顧客資料
def write_customers(customers):
    with open('customer.json', 'w', encoding='utf-8') as file:
        json.dump([customer for customer in customers], file, ensure_ascii=False, indent=4)

# 新增顧客
@app.post("/customers/", response_model=Customer)
async def create_customer(customer: Customer):
    customers = read_customers()

    # 檢查顧客ID是否已存在
    if any(c['id'] == customer.id for c in customers):
        raise HTTPException(status_code=400, detail="Customer ID already exists.")

    customers.append(customer.dict())  # 將 Pydantic 模型轉換為字典並添加到顧客列表
    write_customers(customers)
    return customer

# 獲取所有顧客
@app.get("/customers/", response_model=list)
async def get_customers():
    return read_customers()

執行程式碼 檔案名稱要叫做main.py

uvicorn main:app --reload

執行步驟

  1. 在command line執行指令
  2. 可以從postman來call API : 輸入http://127.0.0.1:8000/customers/ Post
    範例json
{
    "id": 1,
    "name": "王小明",
    "email": "xiaoming@example.com",
    "address": "台北市信義區"
}

https://ithelp.ithome.com.tw/upload/images/20241008/20121052rE2OD3HLrA.png

如果成功,就代表已經學會最基本的post api了~

接下來我們來逐步講解程式碼吧~

pydantic( BaseModel ) 型別處理模組

  1. 數據定義
    BaseModel 允許開發者通過類定義數據結構,並使用 Python 類型註解來指定每個屬性的類型
from pydantic import BaseModel

class Customer(BaseModel):
    id: int
    name: str
    email: str
    address: str = None  
  1. 自動數據驗證

當創建 BaseModel 的實例時,Pydantic 會自動檢查傳入數據的類型,並在不符合時引發錯誤。這樣可以確保數據的一致性和正確性。

3.數據轉換

Pydantic 能夠自動將輸入數據轉換為指定的類型。例如,字符串 "123" 會被轉換為整數 123

Fast API( @Post )

步驟 描述
接收請求 客戶端發送 POST 請求,並附帶一個 Customer 物件。
讀取現有資料 customer.json 中讀取現有顧客資料。
檢查是否存在 檢查是否有相同的顧客 ID,若存在,回應錯誤。
新增資料 若 ID 不存在,將新的顧客資料添加到列表中,並寫入 customer.json
回應客戶端 回應新增的顧客資料,根據 response_model,以 Customer 模型格式返回給客戶端。
  1. @app.post("/customers/", response_model=Customer)
    這行使用了 FastAPI 提供的 路由裝飾器。
  • @app.post 表示這個 API 端點將處理 HTTP POST 請求。
  • "/customers/" 是路由,表示這個端點的 URL 路徑
  • 當使用者對該路徑發送 POST 請求時,會觸發這個函數。

response_model=Customer 表示這個 API 端點將會以 Customer 模型作為回應格式。這意味著,當成功新增顧客後,會以 Customer 的結構回應給客戶端。

  1. async def create_customer(customer: Customer):
  • 異步函數 create_customer,接收一個 Customer 物件作為輸入參數。
  • Customer 是基於 Pydantic 的資料模型
  • 這意味著 FastAPI 會自動驗證傳入的資料是否符合 Customer 的格式和類型要求。
  1. customers = read_customers()
    這行調用了 read_customers() 函數,該函數會從 customer.json 檔案中讀取現有的顧客資料,並以列表形式返回。這些資料稍後會被用來檢查是否已經存在相同的顧客 ID

  2. if any(c['id'] == customer.id for c in customers):
    這行使用 any() 函數來檢查是否有任何現有顧客的 id 與新的 customer.id 相同。

  • any() 函數會遍歷 customers 列表中的每個字典物件 (c)
  • 檢查它們的 id 是否與新的 customer.id 相同。
  • 如果有一個相同,any() 函數會返回 True,表示該顧客ID已經存在。
  1. raise HTTPException(status_code=400, detail="Customer ID already exists.")
    如果前面的 any() 條件成立(即顧客 ID 已存在),這行會拋出一個 HTTP 400 錯誤,告知客戶端這個顧客 ID 已存在。

HTTPException 是 FastAPI 用來拋出 HTTP 錯誤的方式
其中 status_code=400 表示「錯誤的請求」(Bad Request),而 detail 中的訊息會傳回給客戶端。
6. customers.append(customer.dict())
這行將新的顧客資料添加到 customers 列表中。

customer.dict() 是一個 Pydantic 模型的方法,用來將 Pydantic 模型轉換為字典格式。這樣做是因為顧客列表中的每個顧客資料都是字典格式的,為了保持一致性,我們需要將新的顧客資料也轉換為字典。
7. write_customers(customers)
這行呼叫了 write_customers() 函數,將更新後的顧客列表寫入 customer.json 檔案中。這會覆寫原來的資料並將新的顧客資料保存在 JSON 檔案裡。

  1. return customer
    這行將新增的顧客資料(Customer 物件)回應給客戶端。由於 response_model=Customer,這個回應會遵循 Customer 模型的結構,並自動序列化為 JSON 格式傳回給客戶端。

Fast API( @Get )

程式碼部分

@app.get("/customers/", response_model=list)
async def get_customers():
    return read_customers()

操作部分
路由不變,只要改過http method變成GET即可~!!
https://ithelp.ithome.com.tw/upload/images/20241008/20121052w5bVc4fJQy.png

Fast API( @Put )

https://ithelp.ithome.com.tw/upload/images/20241008/201210528Ssu6PttY8.png

實作程式碼

步驟
我們可以透過傳入id參數(比如說前面範例我把id2同樣新增一樣是王小明)
我想要把它改成John

@app.put("/customers/{customer_id}", response_model=Customer)
async def update_customer(customer_id: int, updated_customer: Customer):
    customers = read_customers()

    for i, customer in enumerate(customers):
        if customer['id'] == customer_id:
            customers[i] = updated_customer.dict()
            write_customers(customers)
            return updated_customer

    raise HTTPException(status_code=404, detail="Customer not found")

操作postman

https://ithelp.ithome.com.tw/upload/images/20241008/201210521Z6eWtAadB.png

程式碼解釋

  1. @app.put("/customers/{customer_id}", response_model=Customer)
  • PUT 方法:這是一個 FastAPI 定義的路由,使用 PUT 方法表示更新資源。
  • /customers/{customer_id} 這個路徑表示我們要更新特定的顧客資料,
  • customer_id 是一個動態變數,表示要更新的顧客的 ID。
  • response_model=Customer:這表示當成功更新顧客資料後,API 會回傳一個 Customer 類型的物件
  1. async def update_customer(customer_id: int, updated_customer: Customer):
  • customer_id:從 URL 中傳入的參數,用來指定要更新哪個顧客的 ID。
  • updated_customer:這是一個從請求主體(request body)中傳入的顧客資料,使用 Pydantic 模型 Customer 來驗證資料的結構與內容。
  1. customers = read_customers()
    這行程式碼從 customer.json 檔案中讀取所有現有的顧客資料,並將其存儲在 customers 這個變數中
  2. for i, customer in enumerate(customers):
    使用 enumerate() 函數來遍歷 customers 列表,並同時取得顧客的索引 i 以及對應的顧客資料 customer。這樣可以方便在找到匹配的顧客時進行資料更新。
  3. if customer['id'] == customer_id:
    在迴圈中,這行程式碼檢查是否找到與 customer_id 相同的顧客。如果找到,代表要更新的顧客已存在。
  4. customers[i] = updated_customer.dict()
    當找到指定的顧客時,將 updated_customer 的資料更新到 customers 列表中。這裡使用了 Pydantic 提供的 .dict() 方法,將 Customer 類型的物件轉換為字典格式,這樣資料可以直接存入 customers 列表。
    7.** write_customers(customers)**
    這行程式碼將更新後的 customers 列表寫回到 customer.json 檔案中,保存更改。
  5. return updated_customer
    成功更新後,API 會回傳更新後的顧客資料,這樣客戶端可以看到更新結果。
  6. raise HTTPException(status_code=404, detail="Customer not found")
    如果遍歷完所有顧客後,沒有找到符合 customer_id 的顧客,API 就會拋出一個 HTTP 404 錯誤,表示找不到該顧客。

Fast API( @DELETE )

刪除的邏輯跟更新很像所以我放在同一組=> 一樣是透過ID篩選到然後作操作
刪除只要傳路徑的ID不需要pass Data到後端處理

情境比較簡單就不畫流程圖了XDD
用patch的情境帶入即可

@app.delete("/customers/{customer_id}")
async def delete_customer(customer_id: int):
    customers = read_customers()

    # 過濾掉需要刪除的顧客
    filtered_customers = [customer for customer in customers if customer['id'] != customer_id]

    if len(filtered_customers) == len(customers):
        raise HTTPException(status_code=404, detail="Customer not found")

    write_customers(filtered_customers)
    return {"message": "Customer deleted successfully"}

程式碼解釋

列表生成式:

filtered_customers = [customer for customer in customers if customer['id'] != customer_id]

1.這行代碼創建了一個新的列表,名為 filtered_customers。
它遍歷 customers 列表中的每一個 customer。
2.條件判斷:
if customer['id'] != customer_id:
對於每個 customer,它檢查該顧客的 id 是否不等於傳入的 customer_id。
只有當條件為 True 時,該 customer 才會被包括在新的列表中。
3.過濾效果:
結果是 filtered_customers 列表只包含那些不需要被刪除的顧客。這樣可以在後續操作中用來更新顧客資料,而不包含已經刪除的顧客。

操作結果

https://ithelp.ithome.com.tw/upload/images/20241008/20121052lsDNARtxfo.png

總結

今天我們學會了
軟體評估的重要環節
HTTP Request的重要四大部分
Fast API

明天我們會使用相同的API來做界接
前端不會著墨太多

但是會帶大家看實際是怎麼橋接的~/images/emoticon/emoticon35.gif


上一篇
[Day22] Python專案 - 網頁開發 - (1) 網頁工程師基本知識(設計網站的架構、套件管理、資料庫、API測試工具)
下一篇
[Day24] Python專案 - 網頁開發 - (3) 前端的至尊React與Python之間的交流
系列文
從概念到應用:Python實戰開發學習之旅31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言